<!DOCTYPE html><html lang="zh-CN" data-theme="dark"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Vue源码开发-数据响应式01 | 北城韩雨</title><meta name="keywords" content="Vue"><meta name="author" content="北城韩雨"><meta name="copyright" content="北城韩雨"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#0d0d0d"><meta name="description" content="Vue">
<meta property="og:type" content="article">
<meta property="og:title" content="Vue源码开发-数据响应式01">
<meta property="og:url" content="http://example.com/2021/01/01/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F01/index.html">
<meta property="og:site_name" content="北城韩雨">
<meta property="og:description" content="Vue">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2017-07-20%2F4f06f9aa2ebcea6691a78537052e8e9f%2F00001.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&refer=http%3A%2F%2Fpic.vjshi.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629530599&t=32fb97bad7007bdc6c712ccadacd5721">
<meta property="article:published_time" content="2020-12-31T16:00:00.000Z">
<meta property="article:modified_time" content="2020-12-31T16:00:00.000Z">
<meta property="article:author" content="北城韩雨">
<meta property="article:tag" content="Vue">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2017-07-20%2F4f06f9aa2ebcea6691a78537052e8e9f%2F00001.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&refer=http%3A%2F%2Fpic.vjshi.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629530599&t=32fb97bad7007bdc6c712ccadacd5721"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="http://example.com/2021/01/01/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F01/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'mediumZoom',
  Snackbar: undefined,
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Vue源码开发-数据响应式01',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2021-01-01 00:00:00'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
    const detectApple = () => {
      if (GLOBAL_CONFIG_SITE.isHome && /iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><link rel="stylesheet" href="/css/custom.css"  media="defer" onload="this.media='all'"><link rel="stylesheet" href="/css/coin.css"  media="defer" onload="this.media='all'"><link rel="stylesheet" href="/css/liuxing.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/l-lin/font-awesome-animation/dist/font-awesome-animation.min.css"  media="defer" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper/swiper-bundle.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/zhheo/JS-Heo@main/bb/showbb_in_index.css"><!-- hexo injector head_end start --><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" media="print" onload="this.media='screen'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/l-lin/font-awesome-animation/dist/font-awesome-animation.min.css" media="defer" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-butterfly-tag-plugins-plus/lib/tag_plugins.min.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --><meta name="generator" content="Hexo 5.3.0"></head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/my.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">65</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">23</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/categories/"><div class="headline">分类</div><div class="length-num">21</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/"><i class="fa-fw fas fa-home faa-tada"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/shuoshuo/"><i class="fa-fw fas fa-archive faa-tada"></i><span> 叨逼叨</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/tags/"><i class="fa-fw fas fa-tags faa-tada"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/categories/"><i class="fa-fw fas fa-folder-open faa-tada"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/link/"><i class="fa-fw fas fa-link faa-tada"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/comments/"><svg class="icon faa-tada" aria-hidden="true"><use xlink:href="#icon-message"></use></svg><span> 留言板</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/about/"><i class="fa-fw fas fa-heart faa-tada"></i><span> 个人简介</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2017-07-20%2F4f06f9aa2ebcea6691a78537052e8e9f%2F00001.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&amp;refer=http%3A%2F%2Fpic.vjshi.com&amp;app=2002&amp;size=f9999,10000&amp;q=a80&amp;n=0&amp;g=0n&amp;fmt=jpeg?sec=1629530599&amp;t=32fb97bad7007bdc6c712ccadacd5721')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">北城韩雨</a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/"><i class="fa-fw fas fa-home faa-tada"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/shuoshuo/"><i class="fa-fw fas fa-archive faa-tada"></i><span> 叨逼叨</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/tags/"><i class="fa-fw fas fa-tags faa-tada"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/categories/"><i class="fa-fw fas fa-folder-open faa-tada"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/link/"><i class="fa-fw fas fa-link faa-tada"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/comments/"><svg class="icon faa-tada" aria-hidden="true"><use xlink:href="#icon-message"></use></svg><span> 留言板</span></a></div><div class="menus_item"><a class="site-page faa-parent animated-hover" href="/about/"><i class="fa-fw fas fa-heart faa-tada"></i><span> 个人简介</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Vue源码开发-数据响应式01</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2020-12-31T16:00:00.000Z" title="发表于 2021-01-01 00:00:00">2021-01-01</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2020-12-31T16:00:00.000Z" title="更新于 2021-01-01 00:00:00">2021-01-01</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E6%BA%90%E7%A0%81/">源码</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">7.8k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>28分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="Vue源码开发-数据响应式01"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="Vue源码开发-数据响应式"><a href="#Vue源码开发-数据响应式" class="headerlink" title="Vue源码开发-数据响应式"></a>Vue源码开发-数据响应式</h1><h2 id="rollup-环境搭建"><a href="#rollup-环境搭建" class="headerlink" title="rollup 环境搭建"></a>rollup 环境搭建</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> rollup 是一个单独js打包工具 相比webpack来讲 速度好 编辑好 他更适合开发类库</span><br><span class="line"><span class="number">2.</span> 安装</span><br><span class="line">rollup  <span class="comment">// 打包用的</span></span><br><span class="line">rollup-plugin-babel  <span class="comment">// 让我们的rollup 和 我们的 巴babel 做关联</span></span><br><span class="line">@babel/core <span class="comment">// 编译ES6用的 </span></span><br><span class="line">@babel/preset-env <span class="comment">// 上面会调用这个里面的一些工具 去转换语法</span></span><br><span class="line">rollup-plugin-serve -D <span class="comment">// 启动本地服务的</span></span><br></pre></td></tr></table></figure>
<h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> babel <span class="keyword">from</span> <span class="string">&#x27;rollup-plugin-babel&#x27;</span> <span class="comment">//转换语法的插件</span></span><br><span class="line"><span class="keyword">import</span> serve <span class="keyword">from</span> <span class="string">&#x27;rollup-plugin-serve&#x27;</span> <span class="comment">// 启动服务的插件</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">input:<span class="string">&#x27;./src/index.js&#x27;</span>, <span class="comment">// 你要编译的入口文件</span></span><br><span class="line">output:&#123;</span><br><span class="line">    format:<span class="string">&#x27;umd&#x27;</span>, <span class="comment">// 编译完毕之后是哪中规范 这里我们是在浏览器中使用 所以用umd</span></span><br><span class="line">    name:<span class="string">&#x27;Vue&#x27;</span>, <span class="comment">// 挂在到window上的名字</span></span><br><span class="line">    file:<span class="string">&#x27;dist/umd/vue.js&#x27;</span>, <span class="comment">//打包完输出的目录</span></span><br><span class="line">    sourcemap:<span class="literal">true</span> <span class="comment">//是否开启调试</span></span><br><span class="line">&#125;,</span><br><span class="line">plugins:[</span><br><span class="line">    <span class="comment">// 使用哪个插件去转换语法 这里他会去找我们设置.babelrc里的配置文件</span></span><br><span class="line">    babel(&#123;</span><br><span class="line">        exclude:<span class="string">&#x27;node_modules/**&#x27;</span></span><br><span class="line">    &#125;),</span><br><span class="line">    <span class="comment">//开启一个本地服务</span></span><br><span class="line">    serve(&#123;</span><br><span class="line">        port:<span class="number">3000</span>,</span><br><span class="line">        contentBase:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">        openPage:<span class="string">&#x27;./index.html&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// .babelrc 配置文件 </span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="string">&quot;presets&quot;</span>: [</span><br><span class="line">        <span class="string">&quot;@babel/preset-env&quot;</span></span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 启动脚本</span></span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;name&quot;</span>: <span class="string">&quot;package.json&quot;</span>,</span><br><span class="line">  <span class="string">&quot;version&quot;</span>: <span class="string">&quot;1.0.0&quot;</span>,</span><br><span class="line">  <span class="string">&quot;description&quot;</span>: <span class="string">&quot;&quot;</span>,</span><br><span class="line">  <span class="string">&quot;main&quot;</span>: <span class="string">&quot;index.js&quot;</span>,</span><br><span class="line">  <span class="string">&quot;scripts&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;dev&quot;</span>: <span class="string">&quot;rollup -c -w&quot;</span>,</span><br><span class="line">    <span class="string">&quot;test&quot;</span>: <span class="string">&quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="string">&quot;author&quot;</span>: <span class="string">&quot;&quot;</span>,</span><br><span class="line">  <span class="string">&quot;license&quot;</span>: <span class="string">&quot;ISC&quot;</span>,</span><br><span class="line">  <span class="string">&quot;devDependencies&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;@babel/core&quot;</span>: <span class="string">&quot;^7.12.13&quot;</span>,</span><br><span class="line">    <span class="string">&quot;@babel/preset-env&quot;</span>: <span class="string">&quot;^7.12.13&quot;</span>,</span><br><span class="line">    <span class="string">&quot;rollup&quot;</span>: <span class="string">&quot;^2.38.5&quot;</span>,</span><br><span class="line">    <span class="string">&quot;rollup-plugin-babel&quot;</span>: <span class="string">&quot;^4.4.0&quot;</span>,</span><br><span class="line">    <span class="string">&quot;rollup-plugin-serve&quot;</span>: <span class="string">&quot;^1.1.0&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Vue初始化流程"><a href="#Vue初始化流程" class="headerlink" title="Vue初始化流程"></a>Vue初始化流程</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 初始化 无非就是对我们传进来的参数 做一些列的判断校验</span><br><span class="line"><span class="number">2.</span> 这里为了能更好的扩展 我们一般都会写一个init函数挂在到原型上</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Vue</span>(<span class="params">options</span>)</span>&#123;</span><br><span class="line">  <span class="built_in">this</span>.init(options)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Vue.prototype.init = <span class="function"><span class="keyword">function</span> (<span class="params">options</span>) </span>&#123;...在这里做一些参数的判断&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">但是以上那么写法 不方便我们扩展 如果我们还需要在原型上 写很多方法 我们要写很多的 类似下面的代码 而写都写在一个文件里了 以后在维护的时候也不方便</span><br><span class="line">Vue.prototype.a = <span class="function"><span class="keyword">function</span> (<span class="params">options</span>) </span>&#123;...在这里做一些参数的判断&#125;</span><br><span class="line">Vue.prototype.b = <span class="function"><span class="keyword">function</span> (<span class="params">options</span>) </span>&#123;...在这里做一些参数的判断&#125;</span><br><span class="line">Vue.prototype.c = <span class="function"><span class="keyword">function</span> (<span class="params">options</span>) </span>&#123;...在这里做一些参数的判断&#125;</span><br><span class="line">所以我们为了结偶可以写成一个一个的插件的写法 方便我们以后也扩展</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 我们写一个函数 这个函数 就是为了以后我们拓展用</span><br><span class="line"><span class="number">2.</span> 这个函数的传惨 就是我们的 Vue 然后我们在这个函数体内去 写我们的原型扩展的方法</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 新建 init.js </span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">initMixin</span>(<span class="params">Vue</span>)</span>&#123;</span><br><span class="line">    Vue.prototype._init = <span class="function"><span class="keyword">function</span> (<span class="params">options</span>)</span>&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 然后在我们index.js 导入这个方法 把我们的构造函数传入进去</span></span><br><span class="line"><span class="keyword">import</span> &#123;initMixin&#125; <span class="keyword">from</span> <span class="string">&#x27;./init.js&#x27;</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Vue</span>(<span class="params">options</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>._init(options)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 调用我们写的初始化方法 把我们的Vue 传入禁区</span></span><br><span class="line">initMixin(Vue)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> Vue</span><br></pre></td></tr></table></figure>
<h2 id="初始化状态"><a href="#初始化状态" class="headerlink" title="初始化状态"></a>初始化状态</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 我们上面 已经把初始化的init方法 通过扩展的方式 写成了方法</span><br><span class="line"><span class="number">2.</span> 那么在init方法里面我们就需要初始化状态</span><br><span class="line"><span class="number">3.</span> 这里所谓的状态就是 你传进来的 data(比如要做数据劫持) methods(要绑定方法) computed watch</span><br><span class="line"><span class="number">4.</span> 所以这里我们要在拆分出一个initState的方法 用来初始花我们上面的状态 做对应的处理</span><br><span class="line"><span class="number">5.</span> 所以我们在init方法里面 要把我们的options(就是你传进来的参数) 挂在到我们的实例一份 然后在传入到我们的initaState方法中去 </span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// init.js</span></span><br><span class="line"><span class="keyword">import</span> &#123; initState &#125; <span class="keyword">from</span> <span class="string">&quot;./state&quot;</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">initMixin</span>(<span class="params">Vue</span>)</span>&#123;</span><br><span class="line">    Vue.prototype._init = <span class="function"><span class="keyword">function</span> (<span class="params">options</span>)</span>&#123;</span><br><span class="line">        <span class="comment">// 因为 vue 会把我们的传进来的参数都挂在到我们的实例上的$options</span></span><br><span class="line">        <span class="keyword">const</span> vm = <span class="built_in">this</span></span><br><span class="line">        <span class="comment">// 把传进来的参数 挂在到我们的实例上面</span></span><br><span class="line">        vm.$options = options</span><br><span class="line">      	<span class="comment">// 开始初始化状态</span></span><br><span class="line">        initState(vm)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// state.js</span></span><br><span class="line"><span class="comment">// 开始对我们的传进来的状态 做不同的逻辑处理 比如你的props 不能和 data 重名 如果重名了 我们优先采用props里的</span></span><br><span class="line"><span class="comment">// data 不能和 methods 重名 重名就会报错等等 逻辑处理</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">initState</span>(<span class="params">vm</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">const</span> opts = vm.$options</span><br><span class="line">    <span class="keyword">if</span>(opts.props)&#123;</span><br><span class="line">        initProps(vm)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(opts.methods)&#123;</span><br><span class="line">        initMethods(vm)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(opts.data)&#123;</span><br><span class="line">        initData(vm)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(opts.computed)&#123;</span><br><span class="line">        initComputed(vm)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(opts.watch)&#123;</span><br><span class="line">        initWatch(vm)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 下面是对应的函数处理</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initProps</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initMethods</span> (<span class="params"></span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initData</span> (<span class="params">vm</span>)</span>&#123;</span><br><span class="line">   </span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initComputed</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initWatch</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="数据响应式"><a href="#数据响应式" class="headerlink" title="数据响应式"></a>数据响应式</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 我们这里先对我们的data 做初始化处理</span><br><span class="line"><span class="number">2.</span> 这里就需要劫持你传进来的data 当数据改变的时候 开始劫持</span><br><span class="line"><span class="number">3.</span> 这里我们也是 数据劫持的方法 单独写入一个文件</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 开始判断你传进来的data 是函数 还是对象 是函数 我们就调用 返回一个对象么 如果是对象我们直接就赋值</span></span><br><span class="line"><span class="comment">// 然后把data 传入到我们的 observe 就是我们的数据劫持的方法</span></span><br><span class="line"><span class="comment">// 数据的初始化操作</span></span><br><span class="line"><span class="keyword">import</span> &#123; observe &#125; <span class="keyword">from</span> <span class="string">&quot;./observe/index&quot;</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initData</span> (<span class="params">vm</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> data = vm.$options.data</span><br><span class="line">    <span class="comment">// 1.因为 你传进来的data 可能是函数 用可能是对象 所以这里我们要做判断</span></span><br><span class="line">    <span class="comment">// 如果是函数我们就调用然后返回对象如果不是 我们直接就把data覆盖</span></span><br><span class="line">    <span class="comment">// 这里我们在规定的时候 就知道 调用完完毕时候 肯定是个对象</span></span><br><span class="line">    data = <span class="keyword">typeof</span> data === <span class="string">&#x27;function&#x27;</span>?data.call(vm) : data</span><br><span class="line">    <span class="comment">//2. 数据处理完了 我们开始做数据劫持了 对象 Object.defineProperty</span></span><br><span class="line">    <span class="comment">// 如果这个对象里面还有数组我们就单独处理</span></span><br><span class="line">    <span class="comment">// 这里我们单独把数据劫持的模块拿出去写 observe文件夹 下的index.js</span></span><br><span class="line">    observe(data)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="数据劫持"><a href="#数据劫持" class="headerlink" title="数据劫持"></a>数据劫持</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 这我们数据劫持的核心api 就是 <span class="built_in">Object</span>.defineProperty</span><br><span class="line"><span class="number">2.</span> 我们这里需要劫持的 有对象 有数组 所以这一我们单独写一个类去处理 Observer</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  <span class="function"><span class="title">data</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123; <span class="attr">a</span>: <span class="number">1</span>&#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// state.js </span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initData</span> (<span class="params">vm</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> data = vm.$options.data</span><br><span class="line">    <span class="comment">// 这里我要给我们的数据做劫持 也就是说 我们在给data里的数据 做取值 和 赋值的时候</span></span><br><span class="line">    <span class="comment">// 要触发我们昨晚劫持后的get函数 和我们 set 函数</span></span><br><span class="line">    <span class="comment">// 所以要把这个判断后的数据挂在我们实例上一下</span></span><br><span class="line">    <span class="comment">// 当我们以后用的时候就是 vm._data.a = 200 </span></span><br><span class="line">    vm._data = data = <span class="keyword">typeof</span> data === <span class="string">&#x27;function&#x27;</span>?data.call(vm) : data</span><br><span class="line"> </span><br><span class="line">    observe(data)</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="observe"><a href="#observe" class="headerlink" title="observe"></a>observe</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 如果你传进来的data 如果不是对象 或者 是<span class="literal">null</span> 我们就不做任何处理</span><br><span class="line"><span class="number">2.</span> 这里我们做数据劫持的方法 单独在一些类 如果我们是对象怎么做劫持 如果 是数组怎么做劫持 因为以后这个数据劫持的方法 肯定也还会用到 所以结偶出去</span><br><span class="line"><span class="number">3.</span> 然后我们在单独写个 方法 这个方法 就是 调用了 <span class="built_in">Object</span>.defineProperty 方法</span><br><span class="line"><span class="number">4.</span> 当然这里面还有一些特殊情况 就需要我们去递归的调用 我们的observe方法</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// observe/index.js</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">observe</span>(<span class="params">data</span>)</span>&#123;</span><br><span class="line">    <span class="comment">//1.首先这个data 就是 你在new Vue的时候 传递进来data函数返回的对象</span></span><br><span class="line">    <span class="comment">// 所以我们要对他进行判断 如果不是对象 或者 你穿进来的是个null 我们进行处理 什么也不错 或者抛出错误</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> data !== <span class="string">&#x27;object&#x27;</span> &amp;&amp; data !== <span class="literal">null</span>) <span class="keyword">return</span></span><br><span class="line">    <span class="comment">//2. 然后开始我们的数据劫持  数据劫持的方法 可能在别的地方也会用到 所以我们单独写个类</span></span><br><span class="line">    <span class="keyword">return</span>  <span class="keyword">new</span> Observer(data)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Observer 类</span></span><br><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  <span class="function"><span class="title">data</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      a:<span class="number">1</span>,</span><br><span class="line">      b:<span class="number">2</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Observer</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params">value</span>)</span>&#123;</span><br><span class="line">        <span class="comment">// 这里的value 就是你 new Vue 的时候传进进来的 data 里的数据</span></span><br><span class="line">        <span class="built_in">this</span>.walk(value)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="title">walk</span>(<span class="params">data</span>)</span>&#123;</span><br><span class="line">        <span class="comment">// data =&gt; &#123;a:1,b:2&#125;</span></span><br><span class="line">        <span class="comment">// keys =&gt; [a,b]</span></span><br><span class="line">        <span class="keyword">let</span> keys = <span class="built_in">Object</span>.keys(data)</span><br><span class="line">        keys.forEach( <span class="function"><span class="params">key</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="comment">// key =&gt; a , b</span></span><br><span class="line">            <span class="comment">// data[key] =&gt; 1 , 2</span></span><br><span class="line">            defineReactive(data,key,data[key])</span><br><span class="line">            <span class="comment">// 在 Vue里我们 defineReactive 这个方法 是写在 util 上的</span></span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="defineReactive"><a href="#defineReactive" class="headerlink" title="defineReactive"></a>defineReactive</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 这个方法就是我们的数据劫持的方法</span><br><span class="line"><span class="number">2.</span> 这里的几种情况 如果我们 数据 是&#123;<span class="attr">a</span>:&#123;<span class="attr">a</span>:&#123;<span class="attr">a</span>:<span class="number">1</span>&#125;&#125;&#125; 当我们取值的 a.a.a 我们触发了一次劫持之后的 get 方法 所以要递归一下 当我访问的值还是对象的时候的时候 我们就在调用ovserve方法 递归</span><br><span class="line"><span class="number">3.</span> 当我们 设置的值的时候 如果我们 原来是 &#123;<span class="attr">a</span>:&#123;<span class="attr">a</span>:&#123;<span class="attr">a</span>:<span class="number">1</span>&#125;&#125;&#125; 但是这里我们改变值 a.a.a = &#123;<span class="attr">b</span> : <span class="number">1</span>&#125; 但是我们 在设置值的时候 a.a.a.b =<span class="number">100</span> 这个时候 是触发不了 劫持后的set函数的 所以 我们还在在改变的时候 如果你设置的新值还是个对象 我们就还要调用 observe 一次 并且把我们设置的 &#123;<span class="attr">b</span>:<span class="number">1</span>&#125; 传进去 在进行一次劫持</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//4. 数据劫持的方法</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">defineReactive</span>(<span class="params">data,key,value</span>)</span>&#123;</span><br><span class="line">    <span class="comment">// 4.2  如果我们的 a:1 还好 我们走我们的 Observer</span></span><br><span class="line">    <span class="comment">// 但是如果 我们 a:&#123;a:&#123;a;1&#125;&#125; 所以 我们就需要递归的在去调用我们的observe方法 在接着给我们的属性加get 和 set</span></span><br><span class="line">    <span class="comment">// 所以这也是Vue2性能上的不足 因为嵌套的越深 我们就一层一层递归 导致性能下降</span></span><br><span class="line">    observe(value)</span><br><span class="line">    <span class="comment">// 开始对数据劫持</span></span><br><span class="line">    <span class="built_in">Object</span>.defineProperty(data,key,&#123;</span><br><span class="line">        <span class="comment">// 当你访问data的时候触发get方法</span></span><br><span class="line">        <span class="function"><span class="title">get</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> value</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="comment">// 当你设置值的时候触发 set newValue 就是你设置的值</span></span><br><span class="line">        <span class="function"><span class="title">set</span>(<span class="params">newValue</span>)</span>&#123;</span><br><span class="line">            <span class="comment">//4.1 这里 如果我们原来是 a:1 如果你设置 a=1 我们不应该做处理 因为 你设置的值和你原来设置的一样</span></span><br><span class="line">            <span class="keyword">if</span>(newValue === value) <span class="keyword">return</span> </span><br><span class="line">            <span class="comment">//4.3 如果我们这里重新赋值为了一个对象 这就有又观测不到了 所以我们还需要调用一次observe 把设置的新值传递进去</span></span><br><span class="line">            <span class="comment">// 原本是 a:&#123;a:&#123;a:1&#125;&#125; 现在我们 a.a.a = &#123;b : 1&#125; 这个时候我们在 a.a.a.b =100 这个时候就监测不到了</span></span><br><span class="line">            observe(newValue)</span><br><span class="line">            value = newValue</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="数组的劫持"><a href="#数组的劫持" class="headerlink" title="数组的劫持"></a>数组的劫持</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 我们以上的写法 其实已经已经把数组索引进行拦截了 当你通过索引取值或者赋值的时候 其实是会触发get 和 set 函数的</span><br><span class="line"><span class="number">2.</span> 但是这里存在一个问题 如果你的数组很多的话 几百个元素 我们每项都进行了拦截 就会导致性能下降</span><br><span class="line"><span class="number">3.</span> 而且 在修改数组值的时候我们也很少采用 arr[<span class="number">997</span>] = <span class="number">3</span> 这种写法</span><br><span class="line"><span class="number">4.</span> 所以这里为了性能考虑 我们就不对数组进行劫持  </span><br><span class="line"><span class="number">5.</span> 但是数组数据的时候我们怎么办 所以这里 我们想到 我们只对改变数组的方法进行拦截 </span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">    el:<span class="string">&#x27;#app&#x27;</span>,</span><br><span class="line">    data:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            a:[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    methods:&#123;&#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(vm._data)</span><br><span class="line">vm._data.a.a</span><br><span class="line"></span><br><span class="line"><span class="comment">// 我们打印出来可以看到 对数组的每一项都进行了拦截</span></span><br><span class="line"></span><br><span class="line">a: <span class="built_in">Array</span>(<span class="number">3</span>)</span><br><span class="line"><span class="number">0</span>: <span class="number">1</span></span><br><span class="line"><span class="number">1</span>: <span class="number">2</span></span><br><span class="line"><span class="number">2</span>: <span class="number">3</span></span><br><span class="line">length: <span class="number">3</span></span><br><span class="line">get <span class="number">0</span>: ƒ ()</span><br><span class="line">set <span class="number">0</span>: ƒ (newValue)</span><br><span class="line">get <span class="number">1</span>: ƒ ()</span><br><span class="line">set <span class="number">1</span>: ƒ (newValue)</span><br><span class="line">get <span class="number">2</span>: ƒ ()</span><br><span class="line">set <span class="number">2</span>: ƒ (newValue)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果数组很多的话 我们每一项就都会添加 get 和 set 务必会导致性能下降 所以这里我们支队改变数组的操作进行拦截 触发了我们这些操作 我们采取改变数据</span></span><br></pre></td></tr></table></figure>
<h3 id="重写数组方法"><a href="#重写数组方法" class="headerlink" title="重写数组方法"></a>重写数组方法</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 综合上面的原因 我们知道为了要进行数组的方法</span><br><span class="line"><span class="number">2.</span> 我们在判断的 如果你访问的值 是个数组 我们就在去 重写数组的方法</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 如果当你的数据是这个数组的时候 我们就要重写做劫持 这里劫持的值我们可以改变我们数组的方法</span></span><br><span class="line"><span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">    el:<span class="string">&#x27;#app&#x27;</span>,</span><br><span class="line">    data:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            a:[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    methods:&#123;&#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Observer</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params">value</span>)</span>&#123;</span><br><span class="line">        <span class="comment">// 5. 如果你访问的值是个数组 为了性能考虑 我们只要在改变数组的时候 我们才去做劫持</span></span><br><span class="line">        <span class="comment">// 所以这里我们要重写 你数组里的方法</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="built_in">Array</span>.isArray(value))&#123;</span><br><span class="line">          	<span class="comment">// 这里的value 就是你上面的 a:[1,2,3]</span></span><br><span class="line">            <span class="comment">// 5.1这里我们就要重写数组的方法了 push shift unshift splice sort reverse pop</span></span><br><span class="line">            <span class="comment">// 这我们就要把数组上原有的这些方法重写一下 也就是切片一下</span></span><br><span class="line">            <span class="comment">// 这里的value 就是 我们 data =&gt; &#123;a:[1,2,3]&#125;</span></span><br><span class="line">            <span class="comment">// 然后把这个数组的原型链重写  可以调用我们自己劫持的方法 </span></span><br><span class="line">          	<span class="comment">// arrayMethods就是我们重写的可以改数组的方法</span></span><br><span class="line">            value.__proto__ = arrayMethods</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="comment">// 这里的value 就是你 new Vue 的时候传进进来的 data 里的数据</span></span><br><span class="line">            <span class="built_in">this</span>.walk(value)</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="title">walk</span>(<span class="params">data</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">let</span> keys = <span class="built_in">Object</span>.keys(data)</span><br><span class="line">        keys.forEach( <span class="function"><span class="params">key</span> =&gt;</span> &#123;</span><br><span class="line">            defineReactive(data,key,data[key])</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 我们重写数组的方法 可以做切片</span><br><span class="line"><span class="number">2.</span> 思路就是 如果有 就先调用我们自己的方法里的逻辑。然后 在调用 数组原型上的方法 如果没有 就直接调用数组原型上的方法</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//  observe/array.js</span></span><br><span class="line"><span class="comment">//1.拿到 数组原型上所有的方法</span></span><br><span class="line"><span class="keyword">let</span> oldArrayProtoMethods = <span class="built_in">Array</span>.prototype  </span><br><span class="line"><span class="comment">// 2. 然后我们自己创建一个对象 这个对象上有我们自己的 push shift unshift splice sort reverse pop等方法</span></span><br><span class="line"><span class="comment">// 但是没有的方法 他又会去数组的原型上去找</span></span><br><span class="line"><span class="comment">// 创建一个空对象 并且让 这个空对象的 __proto__ 指向你传进去的</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> arrayMethods = <span class="built_in">Object</span>.create(oldArrayProtoMethods)</span><br><span class="line"><span class="comment">//3. 我们要重新写的方法 可以改变愿数组的的方法</span></span><br><span class="line"><span class="keyword">let</span> methods = [</span><br><span class="line">    <span class="string">&#x27;push&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;pop&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;shift&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;unshift&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;reverse&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;sort&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;splice&#x27;</span></span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="comment">// 4. 添加到我们自己重写的方法 </span></span><br><span class="line"><span class="comment">// 这里当我们调用push的方法 他会先找 arrayMethods.push 方法 </span></span><br><span class="line"><span class="comment">// 如果没有 由于上面我们已经让原型链 指向了 数组的原型 所以还会去数组原型上去找方法</span></span><br><span class="line">methods.forEach( <span class="function"><span class="params">method</span> =&gt;</span> &#123;</span><br><span class="line">    arrayMethods[method] = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 这里就是在我们原有的数组方法做了一个切片 当我们push的时候 先走我们自己写的这个函数 也就是我们自己的逻辑</span></span><br><span class="line">        <span class="comment">// 然后在走 我们数组原型上的push</span></span><br><span class="line">        <span class="keyword">const</span> result = oldArrayProtoMethods[method].apply(<span class="built_in">this</span>,<span class="built_in">arguments</span>)</span><br><span class="line">        <span class="keyword">return</span> result</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">    el:<span class="string">&#x27;#app&#x27;</span>,</span><br><span class="line">    data:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            a:[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    methods:&#123;&#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 当我们调用push 的时候 先走我们 arrayMethods 的push  这个时候我们就知道数组修改了 就可以做一些我们想做的逻辑 比如劫持数据之类的 然后再走我们原始数组的push </span></span><br><span class="line">vm._data.a.push(<span class="number">456</span>)</span><br><span class="line"><span class="comment">// 当我们调用concat的时候 由于我们没有写concat方法 所以 这里 会直接调用我们数组的concat方法</span></span><br></pre></td></tr></table></figure>
<h3 id="对数组数据中的对象再次劫持"><a href="#对数组数据中的对象再次劫持" class="headerlink" title="对数组数据中的对象再次劫持"></a>对数组数据中的对象再次劫持</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 刚才我们只是把数组中的方法做了一个大概的切片 </span><br><span class="line"><span class="number">2.</span> 所以这里存在一个问题 如果我们数组中 每一个元素是个对象 这个时候我们就观测不到了</span><br><span class="line"><span class="number">3.</span> 所以我们就要在继续判断 如果你的数组中是个对象我们就要继续调取我们observe方法 对数组中的对象进行劫持</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 以下这种情况 我们是劫持不到 数组中的对象的</span></span><br><span class="line"><span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">    el:<span class="string">&#x27;#app&#x27;</span>,</span><br><span class="line">    data:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            arr:[&#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>&#125;]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    methods:&#123;&#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 我们打印出来可以看到 数组中的的对象是没有 添加get 和 set 的</span></span><br><span class="line">arr: <span class="built_in">Array</span>(<span class="number">1</span>)</span><br><span class="line"><span class="number">0</span>: &#123;<span class="attr">name</span>: <span class="string">&quot;zs&quot;</span>&#125;</span><br><span class="line">length: <span class="number">1</span></span><br><span class="line">__proto__: <span class="built_in">Array</span></span><br><span class="line">get arr: ƒ ()</span><br><span class="line">set arr: ƒ (newValue)</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 如果数组中的元素是对象的话</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Observer</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params">value</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="built_in">Array</span>.isArray(value))&#123;</span><br><span class="line">            value.__proto__ = arrayMethods</span><br><span class="line">            <span class="comment">// 6. 如果数组中还是个对象所以我们就要再次调用我们的observe方法进行劫持</span></span><br><span class="line">            <span class="comment">// 所以这里我们在单独写一个方法</span></span><br><span class="line">            <span class="built_in">this</span>.observeArray(value)</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="comment">// 这里的value 就是你 new Vue 的时候传进进来的 data 里的数据</span></span><br><span class="line">            <span class="built_in">this</span>.walk(value)</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//6.1 开始劫持书中的每一项</span></span><br><span class="line">    <span class="function"><span class="title">observeArray</span>(<span class="params">value</span>)</span>&#123;</span><br><span class="line">        <span class="comment">//然后开始劫持我们数组中的嘘对象</span></span><br><span class="line">        value.forEach( <span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="comment">//调用我们的observe去进行劫持</span></span><br><span class="line">            observe(item)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="title">walk</span>(<span class="params">data</span>)</span>&#123;...好多代码&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//就给我们数组中的对象有添加了劫持</span></span><br><span class="line">arr: <span class="built_in">Array</span>(<span class="number">1</span>)</span><br><span class="line"><span class="number">0</span>:</span><br><span class="line">name: (...)</span><br><span class="line">get name: ƒ ()</span><br><span class="line">set name: ƒ (newValue)</span><br><span class="line">__proto__: <span class="built_in">Object</span></span><br><span class="line">length: <span class="number">1</span></span><br><span class="line">__proto__: <span class="built_in">Array</span></span><br><span class="line">get arr: ƒ ()</span><br><span class="line">set arr: ƒ (newValue)</span><br></pre></td></tr></table></figure>
<h3 id="对数组中添加数据-对象-在劫持"><a href="#对数组中添加数据-对象-在劫持" class="headerlink" title="对数组中添加数据(对象)在劫持"></a>对数组中添加数据(对象)在劫持</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 上面我们已经通过处理 对我们的数据中的数组类型里的对象 做了在劫持</span><br><span class="line"><span class="number">2.</span> 如果我们 对数组中的数据 进行push unshift 等操作 我们传进数组的数据需要在劫持</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> vm = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">    el:<span class="string">&#x27;#app&#x27;</span>,</span><br><span class="line">    data:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            arr:[&#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>&#125;]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    methods:&#123;&#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 这里我们先去调用我们自己的push 方法 然后 在调用了 数组原型上的push 方法</span></span><br><span class="line"><span class="comment">// 所以这里我们 push 进去的 &#123;age:28&#125; 也许要劫持</span></span><br><span class="line">vm._data.arr.push(&#123;<span class="attr">age</span>:<span class="number">28</span>&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(vm._data.arr)</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// array.js</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//1.拿到 数组原型上所有的方法</span></span><br><span class="line"><span class="keyword">let</span> oldArrayProtoMethods = <span class="built_in">Array</span>.prototype  </span><br><span class="line"><span class="comment">// 2. 然后我们自己创建一个对象 这个对象上有我们自己的 push shift unshift splice sort reverse pop等方法</span></span><br><span class="line"><span class="comment">// 但是没有的方法 他又会去数组的原型上去找</span></span><br><span class="line"><span class="comment">// 创建一个空对象 并且让 这个空对象的 __proto__ 指向你传进去的</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> arrayMethods = <span class="built_in">Object</span>.create(oldArrayProtoMethods)</span><br><span class="line"><span class="comment">//3. 我们要重新写的方法 可以改变愿数组的的方法</span></span><br><span class="line"><span class="keyword">let</span> methods = [</span><br><span class="line">    <span class="string">&#x27;push&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;pop&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;shift&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;unshift&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;reverse&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;sort&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;splice&#x27;</span></span><br><span class="line">]</span><br><span class="line">methods.forEach( <span class="function"><span class="params">method</span> =&gt;</span> &#123;</span><br><span class="line">    arrayMethods[method] = <span class="function"><span class="keyword">function</span> (<span class="params">...args</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">const</span> result = oldArrayProtoMethods[method].apply(<span class="built_in">this</span>,args)</span><br><span class="line">         <span class="comment">//7. 如果我们是向数组里添加了一个对象 那么添加的对象也应该被劫持到 </span></span><br><span class="line">         <span class="comment">// 这两个方法 都是向数组中添加元素 所以我们应该在去劫持你向数组中添加 到元素</span></span><br><span class="line">         <span class="comment">// 这里添加到元素 就是你在调用 vm._data.arr.push(&#x27;arg&#x27;) push方法中的参数</span></span><br><span class="line">         <span class="comment">// 但是这里我们的 数据劫持的 observe 方法 在 另外一个文件</span></span><br><span class="line">        <span class="keyword">let</span> inserted</span><br><span class="line">        <span class="keyword">switch</span>(method)&#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;push&#x27;</span>:</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;unshift&#x27;</span>:</span><br><span class="line">                inserted = args</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;splice&#x27;</span>:</span><br><span class="line">                inserted = args.slice(<span class="number">0</span>,<span class="number">2</span>)</span><br><span class="line">            <span class="keyword">default</span>:</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//7.2 如果我们调用上面的方法却是传进来参数是对象了 我们就需要对你传进来的对象和数据在进行观测</span></span><br><span class="line">        <span class="comment">// 在进行观测 也就是数据在劫持 也就是调用我们 的observe方法 但是这个方法在别的文件</span></span><br><span class="line">        <span class="keyword">if</span>(inserted)&#123;</span><br><span class="line">        <span class="comment">// 7.6 首先这里慢的this我们数据 因为只有我们的数据才会调用push... 这些方法</span></span><br><span class="line">        <span class="comment">// 这里在做数据劫持的时候 我们劫持过的数据 上面就会加上 __ob__ 的自定义属性 他的值就是我们的 数据劫持类 这上面也劫持数组的方法</span></span><br><span class="line">        <span class="comment">// 随意我们向数组中添加对象的时候 就可以再次被劫持到</span></span><br><span class="line">            <span class="built_in">this</span>.__ob__.observeArray(inserted)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Observer</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params">value</span>)</span>&#123;</span><br><span class="line">        <span class="comment">//7.3 如果我们的数据 需要观测 就会走到段逻辑 所以我就给他添加一个自定义属性 __ob__ 表示用来观测</span></span><br><span class="line">        <span class="comment">// 并且为了能在 array.js 里 当我们的数据是数组的时候 调用push unshift方法等 向数组里添加的</span></span><br><span class="line">        <span class="comment">// 数据也能被劫持到 所以我们还要把 劫持的方法写在我们的数据上 这样 我们就可以在array.js中调用我们的observe方法</span></span><br><span class="line">        <span class="built_in">Object</span>.defineProperty(value,<span class="string">&#x27;__ob__&#x27;</span>,&#123;</span><br><span class="line">            enumerable:<span class="literal">false</span>, <span class="comment">// 不可枚举 就是循环不了   </span></span><br><span class="line">            configurable:<span class="literal">false</span>, <span class="comment">// 删不掉</span></span><br><span class="line">            value:<span class="built_in">this</span> <span class="comment">//这的this 就是我们 Observer 类 这样做 是为了能 在array.js 中使用我的 observeArray方法</span></span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="comment">//7.4 这需要注意不能下面哪种写法 这样写 你的__ob__ 就又是一个 Observer实例对象 会一致进行死循环劫持</span></span><br><span class="line">        <span class="comment">//value.__ob__ = this</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="built_in">Array</span>.isArray(value))&#123;</span><br><span class="line">            value.__proto__ = arrayMethods</span><br><span class="line">            <span class="built_in">this</span>.observeArray(value)</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="built_in">this</span>.walk(value)</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="title">observeArray</span>(<span class="params">value</span>)</span>&#123;...&#125;</span><br><span class="line">    <span class="function"><span class="title">walk</span>(<span class="params">data</span>)</span>&#123; ... &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="属性的代理"><a href="#属性的代理" class="headerlink" title="属性的代理"></a>属性的代理</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 当我们访问Vue里面的数据的时候我们直接 vm.数据</span><br><span class="line"><span class="number">2.</span> 而我们现在 访问的方式是 vm._data.数据</span><br><span class="line"><span class="number">3.</span> 所以这里我们需要做一层代理 也就是当我们访问 vm.数据 = vm._data.数据</span><br><span class="line"><span class="number">4.</span> 其实就是给我们的数据再次做了劫持</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// state.js</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//8.1 属性代理的方法 当我们访问 vm.数据 的时候  === vm._data.数据</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">proxy</span>(<span class="params">vm,data,key</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">Object</span>.defineProperty(vm,key,&#123;</span><br><span class="line">        <span class="function"><span class="title">get</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            <span class="comment">// 当我们访问 vm.a  == vm._data.a</span></span><br><span class="line">            <span class="keyword">return</span> vm.data[key]</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="function"><span class="title">set</span>(<span class="params">newValue</span>)</span>&#123;</span><br><span class="line">            <span class="comment">// 当我们设置 vm.a  == vm._data.a</span></span><br><span class="line">            vm.data[key] = newValue</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initData</span> (<span class="params">vm</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> data = vm.$options.data</span><br><span class="line">    vm._data = data = <span class="keyword">typeof</span> data === <span class="string">&#x27;function&#x27;</span>?data.call(vm) : data</span><br><span class="line"></span><br><span class="line">    <span class="comment">//8.属性代理</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">let</span> key <span class="keyword">in</span> data)&#123;</span><br><span class="line">        proxy(vm,<span class="string">&#x27;_data&#x27;</span>,key)</span><br><span class="line">    &#125;</span><br><span class="line">    observe(data)</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><h3 id="初始化流程"><a href="#初始化流程" class="headerlink" title="初始化流程"></a>初始化流程</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 首先我们用 rollup 搭建的开发环境 我们在配置文件里到处去的时候 使用的umd 的规范 所以可以直接在浏览器中使用</span><br><span class="line"><span class="number">2.</span> 我们在<span class="keyword">new</span> Vue 的时候 其实调用了 init 函数 并且把我们的参数传入了进去</span><br><span class="line"><span class="number">3.</span> 调用init 函数的时候 我们为了能够以后能更好的扩展 所以没有 直接写在Vue.prototype.init = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125;</span><br><span class="line"><span class="number">4.</span> 而是单独用了一个函数 initMixin 函数 并且 把Vue 作为参数传入了进去 然后在 initMixin函数里面 我们在Vue.prototype 上添加了init 方法</span><br><span class="line"><span class="number">5.</span> init方法 主要把你传进来的参数 挂在到了实例$options属性上 然后开始 调用了 initState函数 把Vue传了进去 initState函数主要是用来初始化状态的</span><br><span class="line"><span class="number">6.</span> 在initState函数里我们的参数就是你传进来的 Vue 上面有一个$options 就是我们传进来的参数 然后我们分别根据你传进来的参数  做了不同的初始化 </span><br><span class="line"><span class="built_in">this</span>.$options.props ? -&gt; initProps(<span class="built_in">this</span>)</span><br><span class="line"><span class="built_in">this</span>.$options.methods ? -&gt; initMthods(<span class="built_in">this</span>)</span><br><span class="line"><span class="built_in">this</span>.$options.data ? -&gt; initData(<span class="built_in">this</span>)</span><br><span class="line"><span class="built_in">this</span>.$options.computed ? -&gt; initComputed(<span class="built_in">this</span>)</span><br><span class="line"><span class="built_in">this</span>.$options.watch ? -&gt; initWatch(<span class="built_in">this</span>)</span><br><span class="line"><span class="number">7.</span> initData 当法 这个就是我们数据劫持的方法</span><br></pre></td></tr></table></figure>
<h3 id="初始化data"><a href="#初始化data" class="headerlink" title="初始化data"></a>初始化data</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> initData 方法中 我们知道 你的数据都在data中 所以我们要判断你的$options中的data 可能一个函数返回一个对象 也可能直接就是一个对象 所以我们要校验一下</span><br><span class="line"><span class="number">2.</span> 然后我们做了一层代理 让我们可以是用 <span class="built_in">this</span>.数据 就可以访问data中的数据 这里也是用了属性代理</span><br><span class="line"><span class="number">3.</span> 然后我们创建了一个observe文件夹 index.js 创建一个 observe方法 做数据截止 把我们的 data 中的数据传入禁区 做了劫持</span><br></pre></td></tr></table></figure>
<h3 id="data的数据劫持"><a href="#data的数据劫持" class="headerlink" title="data的数据劫持"></a>data的数据劫持</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 数据劫持的核心api 就是 <span class="built_in">Object</span>.defineProperty 给你的对象上添加get 和 set 函数 </span><br><span class="line"><span class="number">2.</span> 所以这里我们创建了一个 <span class="class"><span class="keyword">class</span> <span class="title">Observer</span> 的类 分别来给我们不同的数据类型 做不同的数据劫持</span></span><br><span class="line"><span class="class">3. <span class="title">defineReactive</span>方法 给我们的数据做劫持 方法 核心<span class="title">API</span>就是 <span class="title">Object</span>.<span class="title">defineProperty</span></span></span><br><span class="line"><span class="class">4. 所以 当我们在调用 <span class="title">observe</span> 的方法的时候 他会 <span class="title">new</span> <span class="title">Observer</span> 并且返回了这个类的实例</span></span><br></pre></td></tr></table></figure>
<h3 id="第一种情况"><a href="#第一种情况" class="headerlink" title="第一种情况"></a>第一种情况</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 第一种情况 当我们的数据 就是 &#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">18</span>&#125;</span><br><span class="line"><span class="number">2.</span> 那我们直接就调用 Observer 的 walk 方法 并且 把 &#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">18</span>&#125; 传入进去</span><br><span class="line"><span class="number">3.</span> walk 方法 会把  &#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">18</span>&#125; 循环 调用 defineReactive方法 并且 把 对象 &#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">18</span>&#125; 属性 name,age  值 <span class="string">&#x27;zs&#x27;</span>,<span class="number">18</span> 分别传入 defineReactive方法中 然后开始使用API <span class="built_in">Object</span>.defineProperty 给每个属性添加get 和 set 函数</span><br></pre></td></tr></table></figure>
<h3 id="第二种情况"><a href="#第二种情况" class="headerlink" title="第二种情况"></a>第二种情况</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 第二种情况 当我们的数据 &#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">18</span>,obj&#123;<span class="attr">sex</span>:<span class="string">&#x27;男&#x27;</span>,<span class="attr">skill</span>:<span class="string">&#x27;web&#x27;</span>&#125;&#125; </span><br><span class="line"><span class="number">2.</span> 这里我们 obj又是一个对象 所以 还需要在对他进行劫持 调用 observe方法 </span><br><span class="line"><span class="number">3.</span> 所以这个时候 我们在每次 defineReactive方法 开始的时候 在调用一次 observe方法 因为是循环调用的 所以 第一次我们传入的 observe方法放中的是 <span class="string">&#x27;zs&#x27;</span> 第二次 传入 observe方法放中的是 <span class="number">18</span> 第三次传入  observe方法放中的是 obj:&#123;<span class="attr">sex</span>:<span class="string">&#x27;男&#x27;</span>,<span class="attr">skill</span>:<span class="string">&#x27;web&#x27;</span>&#125;&#125;</span><br><span class="line"><span class="number">4.</span> 我们 observe方法中在最开始的时候就会判断 如果你传进来的不是对象 我们就 <span class="keyword">return</span> 所以 第三次传入的 obj 就又会执行 observe 方法 去给 obj中的每个属性 做劫持 添加了 get 和 set 方法 </span><br></pre></td></tr></table></figure>
<h3 id="第三种情况"><a href="#第三种情况" class="headerlink" title="第三种情况"></a>第三种情况</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 当我们做好数据劫持 访问数据的时候 会get方法 改变数据的时候 会触发set方法</span><br><span class="line"><span class="number">2.</span> 所以当我们的数据 是 &#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>&#125;的时候 当我们访问 <span class="built_in">this</span>.name 会触发我们 get 方法 当我们 使用 <span class="built_in">this</span>.name = <span class="string">&#x27;ls&#x27;</span> 的时候 会触发set方法</span><br><span class="line"><span class="number">3.</span> 所以第三种情况是 当我们设置值的时候 这个值是个对象 这个时候我们就劫持不到了 <span class="built_in">this</span>.name = &#123;<span class="attr">obj</span>:<span class="number">11</span>&#125; 这种情况我们就需要对 你重新设置的值 &#123;<span class="attr">obj</span>:<span class="number">11</span>&#125; 重新做劫持</span><br><span class="line"><span class="number">4.</span> 所以 当我们复制的时候 会触发set 函数 默认形参 就是你的改变的值 也就是&#123;<span class="attr">obj</span>:<span class="number">11</span>&#125; </span><br><span class="line"><span class="number">5.</span> 这个时候 我们就在set函数调用你一次 observe 把set 函数里的形参传入到我们的observe 也就是 &#123;<span class="attr">obj</span>:<span class="number">11</span>&#125;</span><br><span class="line"><span class="number">6.</span> 这样就给我们后赋值的类型如果又是对象类型 做了一次劫持</span><br></pre></td></tr></table></figure>
<h3 id="数组数据情况"><a href="#数组数据情况" class="headerlink" title="数组数据情况"></a>数组数据情况</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 第四种情况 当我们的数据 是 &#123;<span class="attr">arr</span>:[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]&#125;</span><br><span class="line"><span class="number">2.</span> 其实我们上面的种种方法 已经可以对们数据中arr 做劫持了 会给数组中的索引 添加 get set 方法 当我们访问arr[<span class="number">0</span>]的时候 触发get 赋值的时候 触发 set 但是我们这种操作很少</span><br><span class="line"><span class="number">3.</span> 但是这里会有一个问题 如果我们的数组 有几千个 几万个 都会给我们所有数组中的索引做劫持 这样就会浪费性能</span><br><span class="line"><span class="number">4.</span> 所以我们对数组类型的数据 单独做处理</span><br><span class="line"><span class="number">5.</span> 所以我们在 <span class="class"><span class="keyword">class</span> <span class="title">Observer</span> 在添加一个方法 <span class="title">observeArray</span> 如果判断 你传进来的 数据是个数组我们在去做单独的处理</span></span><br></pre></td></tr></table></figure>
<h3 id="数组数据情况一"><a href="#数组数据情况一" class="headerlink" title="数组数据情况一"></a>数组数据情况一</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 数组情况一 &#123;<span class="attr">arr</span>:[&#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>&#125;,&#123;<span class="attr">name</span>:<span class="string">&#x27;ls&#x27;</span>&#125;]&#125; 数组中的每个元素都是对象 </span><br><span class="line"><span class="number">2.</span> 我们就用我们的 observeArray方法 把arr传入进去</span><br><span class="line"><span class="number">3.</span> observeArray 方法 会循环你的数组 然后调用我们的劫持方法observe 把数组中的每一项传入进去</span><br></pre></td></tr></table></figure>
<h3 id="数组数据情况二"><a href="#数组数据情况二" class="headerlink" title="数组数据情况二"></a>数组数据情况二</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 数组情况二 &#123;<span class="attr">arr</span>:[&#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>&#125;,&#123;<span class="attr">name</span>:<span class="string">&#x27;ls&#x27;</span>&#125;]&#125; 当我们使用<span class="built_in">this</span>.arr.push(&#123;<span class="attr">name</span>:<span class="string">&#x27;ww&#x27;</span>&#125;)的时候 你push进去 &#123;<span class="attr">name</span>:<span class="string">&#x27;ww&#x27;</span>&#125; 是劫持不到的 所以这些 数组的push unshift pop shift sort splice reverse 都是改变原有数组的这些方法 这些方法 都是js 内置类  而传进去的参数 你都是拿不到的 所以也就调用不了 observe 方法 做不了劫持</span><br><span class="line"><span class="number">2.</span> 所以我们就要重新写这个方法 做个切片 就是当你调用push 的方法的时候 我们先走我们自己的push方法 然后在走你原型上的push方法</span><br><span class="line"><span class="number">3.</span>我们知道 我们数据劫持调用的是observe方法 参数是你的数据 你所有的数据 肯定是定义在一个对象里面 然后我们把数据传入了 我们 observe 中的 <span class="class"><span class="keyword">class</span> <span class="title">Observer</span> 类里 这个类 然后循环你传进来的数据 每一项 再去根据不同的数据类型调用 <span class="title">observe</span>方法 走数据劫持</span></span><br><span class="line"><span class="class">4. 所以当我们数据是数组的时候 会走到 <span class="title">class</span> <span class="title">Observer</span> 判断条件里 那么在这里 我们开始对数组上的方法重写 就是按照我们上面的分析</span></span><br><span class="line"><span class="class">6. 我们知道 <span class="title">arr</span>.<span class="title">__proto__</span> 原型链 指向我们的 <span class="title">Array</span>.<span class="title">prototype</span> 原型 在原型上有<span class="title">push</span> <span class="title">unshift</span> ... 等等方法</span></span><br><span class="line"><span class="class">7. 所以这个时候 我们就创建一个 空对象 让这个空对象的<span class="title">__proto__</span>  指向 <span class="title">Array</span>.<span class="title">prototype</span> 然后在这个空对象上我们在写我们的<span class="title">push</span> <span class="title">unshift</span>... 等等方法 </span></span><br><span class="line"><span class="class">8. 然后在让我们的 <span class="title">arr</span>.<span class="title">__proto__</span> 指向我们的刚刚创建的空对象 </span></span><br><span class="line"><span class="class">9. 这样我们在调取我们的<span class="title">arr</span>.<span class="title">push</span> 的时候 他会顺着原型链去找<span class="title">push</span> 方法 首先找到的是我们的<span class="title">push</span>方法 这个时候我在我们的<span class="title">push</span>方法中就可以拿到参数 然后做劫持 然后在我们自己的<span class="title">push</span>方法中在调用我们数组原型上的方法</span></span><br><span class="line"><span class="class">10. 以上的操作 就可以做到切片</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 以上我们重写的方法是在一个array.js 文件中去完成的 </span><br><span class="line"><span class="number">2.</span> 首先我们会创建一个 空对象 <span class="built_in">Object</span>.create(<span class="built_in">Array</span>.prototype)</span><br><span class="line"><span class="number">3.</span> 然后把创建的空对象到处去 然后在 <span class="class"><span class="keyword">class</span> <span class="title">Observer</span> 文件中 判断数组哪里 让参数.<span class="title">__proto__</span> 等于我们的这个对象</span></span><br><span class="line"><span class="class">4. 然后我们 把我们重写的方法 列在一个数组中 循环这个数组 把每一项都写入到我们创建的空对象中 值是一个函数</span></span><br><span class="line"><span class="class">5. 然后在这个函数里 调用我们的 <span class="title">Array</span>.<span class="title">prototype</span> 原型上的方法 并且改变 <span class="title">this</span> 并且把我们的参数传入进去</span></span><br><span class="line"><span class="class">6. 然后在这个函数里 我们需要把你<span class="title">push</span> <span class="title">unshift</span> ...等等 你进来的参数 继续调用 <span class="title">class</span> <span class="title">Observer</span> 进行数据劫持</span></span><br><span class="line"><span class="class">7. 所以问题来了 <span class="title">class</span> <span class="title">Observer</span> 是在另外一个文件里 我们怎么调用我们的 <span class="title">observeArray</span>方法</span></span><br><span class="line"><span class="class">8. 这我们在 <span class="title">class</span> <span class="title">Observer</span> <span class="title">constructor</span> 里给我们传进来的数据都自定义个属性 叫<span class="title">__ob__</span> 这个属性 这个属性的值就是我们的 <span class="title">class</span> <span class="title">Observer</span></span></span><br><span class="line"><span class="class">9. 所以我们就可以在 <span class="title">array</span>.<span class="title">js</span>文件里 当调用了我们自己的<span class="title">push</span> <span class="title">unshift</span> 等等 方法的时候 就可以使用我们的<span class="title">__ob__</span>上的  <span class="title">class</span> <span class="title">Observer</span> 中的方法了</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span>所以这里 我们就可以 在observe 的时候 最开始就判断一下 你传进来的数据 有没有__ob__ 如果有 就说明你已经被劫持过了 我们就什么也不做</span><br></pre></td></tr></table></figure>
</article><div class="post-copyright"><div class="post-copyright__title"><span class="post-copyright-info"><h>Vue源码开发-数据响应式01</h></span></div><div class="post-copyright__type"><span class="post-copyright-info"><a href="http://example.com/2021/01/01/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F01/">http://example.com/2021/01/01/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F01/</a></span></div><div class="post-copyright-m"><div class="post-copyright-m-info"><div class="post-copyright-a"><h>作者</h><div class="post-copyright-cc-info"><h>北城韩雨</h></div></div><div class="post-copyright-c"><h>发布于</h><div class="post-copyright-cc-info"><h>2021-01-01</h></div></div><div class="post-copyright-u"><h>更新于</h><div class="post-copyright-cc-info"><h>2021-01-01</h></div></div><div class="post-copyright-c"><h>许可协议</h><div class="post-copyright-cc-info"><a class="icon" rel="noopener" target="_blank" title="Creative Commons" href="https://creativecommons.org/"><i class="fab fa-creative-commons"></i></a><a rel="noopener" target="_blank" title="CC BY-NC-SA 4.0" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a></div></div></div></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Vue/">Vue</a></div><div class="post_share"></div></div><link rel="stylesheet" href="/" media="defer" onload="this.media='all'"/><div class="post-reward"><button class="tip-button reward-button"><span class="tip-button__text">打赏</span><div class="coin-wrapper"><div class="coin"><div class="coin__middle"></div><div class="coin__back"></div><div class="coin__front"></div></div></div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="/img/weixin.jpg" target="_blank"><img class="post-qr-code-img" src="/img/weixin.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="/img/taobao.jpg" target="_blank"><img class="post-qr-code-img" src="/img/taobao.jpg" alt="支付宝"/></a><div class="post-qr-code-desc">支付宝</div></li></ul></div></button></div><script defer="defer" src="/"></script><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2021/01/02/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E6%A8%A1%E6%9D%BF%E8%A7%A3%E6%9E%9002/"><img class="prev-cover" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fcz-video-photo.oss-cn-beijing.aliyuncs.com%2F20191017%2F4cfc341591d242327b67e9ceb6953612_00002.jpg&amp;refer=http%3A%2F%2Fcz-video-photo.oss-cn-beijing.aliyuncs.com&amp;app=2002&amp;size=f9999,10000&amp;q=a80&amp;n=0&amp;g=0n&amp;fmt=jpeg?sec=1629530702&amp;t=80943e12d5239f63beafd6d1c540855f" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Vue源码开发-模版解析02</div></div></a></div><div class="next-post pull-right"><a href="/2020/04/27/%E5%86%99%E4%B8%80%E4%B8%AA%E7%AE%80%E7%89%88%E7%9A%84Promise/"><img class="next-cover" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2017-07-20%2F4f06f9aa2ebcea6691a78537052e8e9f%2F00001.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&amp;refer=http%3A%2F%2Fpic.vjshi.com&amp;app=2002&amp;size=f9999,10000&amp;q=a80&amp;n=0&amp;g=0n&amp;fmt=jpeg?sec=1629530599&amp;t=32fb97bad7007bdc6c712ccadacd5721" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">手写一个简版的promise</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span> 相关推荐</span></div><div class="relatedPosts-list"><div><a href="/2021/04/16/gin-vue-admin/" title="Gin-Vue-Admin"><img class="cover" src="/img/gin-vue-admin.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-04-16</div><div class="title">Gin-Vue-Admin</div></div></a></div><div><a href="/2021/01/08/Vue源码开发之组件的渲染10/" title="Vue源码开发-组件的渲染10"><img class="cover" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2018-07-17%2F3eca5394963b50e37b7be2ba320029ec%2F00003.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&refer=http%3A%2F%2Fpic.vjshi.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629530644&t=10679b5732c52e39eeb588040240a790" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-01-08</div><div class="title">Vue源码开发-组件的渲染10</div></div></a></div><div><a href="/2021/01/07/Vue源码开发之组件的合并策略09/" title="Vue源码开发-组件合并策略09"><img class="cover" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fcz-video-photo.oss-cn-beijing.aliyuncs.com%2F20191017%2F4cfc341591d242327b67e9ceb6953612_00002.jpg&refer=http%3A%2F%2Fcz-video-photo.oss-cn-beijing.aliyuncs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629530702&t=80943e12d5239f63beafd6d1c540855f" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-01-07</div><div class="title">Vue源码开发-组件合并策略09</div></div></a></div><div><a href="/2021/01/06/Vue源码开发之数组的依赖收集08/" title="Vue源码开发-数组的依赖收集08"><img class="cover" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2018-07-17%2F3eca5394963b50e37b7be2ba320029ec%2F00003.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&refer=http%3A%2F%2Fpic.vjshi.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629530644&t=10679b5732c52e39eeb588040240a790" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-01-06</div><div class="title">Vue源码开发-数组的依赖收集08</div></div></a></div><div><a href="/2021/01/06/Vue源码开发之生命周期合并07/" title="Vue源码开发-生命周期合并07"><img class="cover" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2018-07-17%2Faf41dabad727ba80c9ca8a2bfbd22a58%2F00004.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&refer=http%3A%2F%2Fpic.vjshi.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629530659&t=bbcfe1e86f393eecbb0722db1b92e475" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-01-06</div><div class="title">Vue源码开发-生命周期合并07</div></div></a></div><div><a href="/2021/01/05/Vue源码开发之批量更新06/" title="Vue源码开发-批量更新06"><img class="cover" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2018-07-17%2F3eca5394963b50e37b7be2ba320029ec%2F00003.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&refer=http%3A%2F%2Fpic.vjshi.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629530644&t=10679b5732c52e39eeb588040240a790" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-01-05</div><div class="title">Vue源码开发-批量更新06</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="/img/my.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">北城韩雨</div><div class="author-info__description">一个前端界的小学生</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">65</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">23</div></a></div><div class="card-info-data-item is-center"><a href="/categories/"><div class="headline">分类</div><div class="length-num">21</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/wazer1987"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="/wangzhengvslike@163.com" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content"><p>感谢访问本站，如喜欢请收藏。本站主要分享前端知识，立志成为资深前端工程师，但目前是一个前端界的小学生 若喜欢可以打赏请博主喝一杯冰阔落</p> <p>另外请大家多多支持淼哥的开源项目</p> <p>https://github.com/flipped-aurora/gin-vue-admin</p> <p>🌟🌟欢迎大家start 🌟🌟</p> <p>欢迎加入博主的前端技术交流群</p> <p style="background:rgba(255,255,255,1);margin:0"> <img src="/img/code.png"></img> </p></div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91-%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F"><span class="toc-text">Vue源码开发-数据响应式</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#rollup-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA"><span class="toc-text">rollup 环境搭建</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE"><span class="toc-text">配置</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Vue%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B"><span class="toc-text">Vue初始化流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E7%8A%B6%E6%80%81"><span class="toc-text">初始化状态</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F"><span class="toc-text">数据响应式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE%E5%8A%AB%E6%8C%81"><span class="toc-text">数据劫持</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#observe"><span class="toc-text">observe</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#defineReactive"><span class="toc-text">defineReactive</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E7%BB%84%E7%9A%84%E5%8A%AB%E6%8C%81"><span class="toc-text">数组的劫持</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%87%8D%E5%86%99%E6%95%B0%E7%BB%84%E6%96%B9%E6%B3%95"><span class="toc-text">重写数组方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AF%B9%E6%95%B0%E7%BB%84%E6%95%B0%E6%8D%AE%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%86%8D%E6%AC%A1%E5%8A%AB%E6%8C%81"><span class="toc-text">对数组数据中的对象再次劫持</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AF%B9%E6%95%B0%E7%BB%84%E4%B8%AD%E6%B7%BB%E5%8A%A0%E6%95%B0%E6%8D%AE-%E5%AF%B9%E8%B1%A1-%E5%9C%A8%E5%8A%AB%E6%8C%81"><span class="toc-text">对数组中添加数据(对象)在劫持</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B1%9E%E6%80%A7%E7%9A%84%E4%BB%A3%E7%90%86"><span class="toc-text">属性的代理</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B0%8F%E7%BB%93"><span class="toc-text">小结</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B"><span class="toc-text">初始化流程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96data"><span class="toc-text">初始化data</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#data%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8A%AB%E6%8C%81"><span class="toc-text">data的数据劫持</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AC%AC%E4%B8%80%E7%A7%8D%E6%83%85%E5%86%B5"><span class="toc-text">第一种情况</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AC%AC%E4%BA%8C%E7%A7%8D%E6%83%85%E5%86%B5"><span class="toc-text">第二种情况</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AC%AC%E4%B8%89%E7%A7%8D%E6%83%85%E5%86%B5"><span class="toc-text">第三种情况</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E7%BB%84%E6%95%B0%E6%8D%AE%E6%83%85%E5%86%B5"><span class="toc-text">数组数据情况</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E7%BB%84%E6%95%B0%E6%8D%AE%E6%83%85%E5%86%B5%E4%B8%80"><span class="toc-text">数组数据情况一</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%95%B0%E7%BB%84%E6%95%B0%E6%8D%AE%E6%83%85%E5%86%B5%E4%BA%8C"><span class="toc-text">数组数据情况二</span></a></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/2021/04/16/gin-vue-admin/" title="Gin-Vue-Admin"><img src="/img/gin-vue-admin.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Gin-Vue-Admin"/></a><div class="content"><a class="title" href="/2021/04/16/gin-vue-admin/" title="Gin-Vue-Admin">Gin-Vue-Admin</a><time datetime="2021-04-15T16:00:00.000Z" title="发表于 2021-04-16 00:00:00">2021-04-16</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2021/01/08/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E7%BB%84%E4%BB%B6%E7%9A%84%E6%B8%B2%E6%9F%9310/" title="Vue源码开发-组件的渲染10"><img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2018-07-17%2F3eca5394963b50e37b7be2ba320029ec%2F00003.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&amp;refer=http%3A%2F%2Fpic.vjshi.com&amp;app=2002&amp;size=f9999,10000&amp;q=a80&amp;n=0&amp;g=0n&amp;fmt=jpeg?sec=1629530644&amp;t=10679b5732c52e39eeb588040240a790" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Vue源码开发-组件的渲染10"/></a><div class="content"><a class="title" href="/2021/01/08/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E7%BB%84%E4%BB%B6%E7%9A%84%E6%B8%B2%E6%9F%9310/" title="Vue源码开发-组件的渲染10">Vue源码开发-组件的渲染10</a><time datetime="2021-01-07T16:00:00.000Z" title="发表于 2021-01-08 00:00:00">2021-01-08</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2021/01/07/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E7%BB%84%E4%BB%B6%E7%9A%84%E5%90%88%E5%B9%B6%E7%AD%96%E7%95%A509/" title="Vue源码开发-组件合并策略09"><img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fcz-video-photo.oss-cn-beijing.aliyuncs.com%2F20191017%2F4cfc341591d242327b67e9ceb6953612_00002.jpg&amp;refer=http%3A%2F%2Fcz-video-photo.oss-cn-beijing.aliyuncs.com&amp;app=2002&amp;size=f9999,10000&amp;q=a80&amp;n=0&amp;g=0n&amp;fmt=jpeg?sec=1629530702&amp;t=80943e12d5239f63beafd6d1c540855f" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Vue源码开发-组件合并策略09"/></a><div class="content"><a class="title" href="/2021/01/07/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E7%BB%84%E4%BB%B6%E7%9A%84%E5%90%88%E5%B9%B6%E7%AD%96%E7%95%A509/" title="Vue源码开发-组件合并策略09">Vue源码开发-组件合并策略09</a><time datetime="2021-01-06T16:00:00.000Z" title="发表于 2021-01-07 00:00:00">2021-01-07</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2021/01/06/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E6%95%B0%E7%BB%84%E7%9A%84%E4%BE%9D%E8%B5%96%E6%94%B6%E9%9B%8608/" title="Vue源码开发-数组的依赖收集08"><img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2018-07-17%2F3eca5394963b50e37b7be2ba320029ec%2F00003.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&amp;refer=http%3A%2F%2Fpic.vjshi.com&amp;app=2002&amp;size=f9999,10000&amp;q=a80&amp;n=0&amp;g=0n&amp;fmt=jpeg?sec=1629530644&amp;t=10679b5732c52e39eeb588040240a790" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Vue源码开发-数组的依赖收集08"/></a><div class="content"><a class="title" href="/2021/01/06/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E6%95%B0%E7%BB%84%E7%9A%84%E4%BE%9D%E8%B5%96%E6%94%B6%E9%9B%8608/" title="Vue源码开发-数组的依赖收集08">Vue源码开发-数组的依赖收集08</a><time datetime="2021-01-05T16:00:00.000Z" title="发表于 2021-01-06 00:00:00">2021-01-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2021/01/06/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%90%88%E5%B9%B607/" title="Vue源码开发-生命周期合并07"><img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.vjshi.com%2F2018-07-17%2Faf41dabad727ba80c9ca8a2bfbd22a58%2F00004.jpg%3Fx-oss-process%3Dstyle%2Fwatermark&amp;refer=http%3A%2F%2Fpic.vjshi.com&amp;app=2002&amp;size=f9999,10000&amp;q=a80&amp;n=0&amp;g=0n&amp;fmt=jpeg?sec=1629530659&amp;t=bbcfe1e86f393eecbb0722db1b92e475" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Vue源码开发-生命周期合并07"/></a><div class="content"><a class="title" href="/2021/01/06/Vue%E6%BA%90%E7%A0%81%E5%BC%80%E5%8F%91%E4%B9%8B%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%90%88%E5%B9%B607/" title="Vue源码开发-生命周期合并07">Vue源码开发-生命周期合并07</a><time datetime="2021-01-05T16:00:00.000Z" title="发表于 2021-01-06 00:00:00">2021-01-06</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright"><span>&copy;2017 - 2021</span><svg style="width:2em; height:2em;position: relative;top: 10px;" aria-hidden="true"><use xlink:href="#icon-Butterfly"></use></svg><span>北城韩雨</span></div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><p><a style="margin-inline:5px" target="_blank" href="https://hexo.io/"><img src="https://img.shields.io/badge/Frame-Hexo-blue?style=flat&logo=hexo" title="博客框架为Hexo"></a><a style="margin-inline:5px" target="_blank" href="https://butterfly.js.org/"><img src="https://img.shields.io/badge/Theme-Butterfly-6513df?style=flat&logo=bitdefender" title="主题采用butterfly"></a><a style="margin-inline:5px" target="_blank" href="https://www.jsdelivr.com/"><img src="https://img.shields.io/badge/CDN-jsDelivr-orange?style=flat&logo=jsDelivr" title="本站使用JsDelivr为静态资源提供CDN加速"></a></p></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/medium-zoom/dist/medium-zoom.min.js"></script><div class="js-pjax"></div><script defer src="/live2d-widget/autoload.js"></script><script src="/js/coin.js"></script><script async src="//at.alicdn.com/t/font_2700632_3rtvhzzpl3h.js"></script><script src="/js/liuxing.js" data-pjax></script><canvas class="fireworks" mobile="false"></canvas><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/fireworks.min.js"></script><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/activate-power-mode.min.js"></script><script>POWERMODE.colorful = true;
POWERMODE.shake = true;
POWERMODE.mobile = false;
document.body.addEventListener('input', POWERMODE);
</script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><!-- hexo injector body_end start --><div class="js-pjax"><script async="async">var arr = document.getElementsByClassName('recent-post-item');
for(var i = 0;i<arr.length;i++){
    arr[i].classList.add('wow');
    arr[i].classList.add('animate__zoomIn');
    arr[i].setAttribute('data-wow-duration', '1s');
    arr[i].setAttribute('data-wow-delay', '0ms');
    arr[i].setAttribute('data-wow-offset', '100');
    arr[i].setAttribute('data-wow-iteration', '1');
  }</script><script async="async">var arr = document.getElementsByClassName('card-widget');
for(var i = 0;i<arr.length;i++){
    arr[i].classList.add('wow');
    arr[i].classList.add('animate__zoomIn');
    arr[i].setAttribute('data-wow-duration', '');
    arr[i].setAttribute('data-wow-delay', '');
    arr[i].setAttribute('data-wow-offset', '');
    arr[i].setAttribute('data-wow-iteration', '');
  }</script></div><script defer src="https://cdn.jsdelivr.net/gh/graingert/wow@1.3.0/dist/wow.min.js"></script><script defer src="https://cdn.jsdelivr.net/npm/hexo-butterfly-wowjs/lib/wow_init.min.js"></script><script async src="//at.alicdn.com/t/font_2032782_8d5kxvn09md.js"></script><!-- hexo injector body_end end --></body></html>